#include "jugador.h"

/** Con el constructor de jugador al crear el objeto lo situamos en la posición que queramos (X,Y)
 * e inicializamos el socket en la dirección y puerto de escucha correspondiente (se encarga el socket)
 * posteriormente recibimos la información inicial del servidor y se la pasamos a la función interpretar
 * y así podremos actuar en consecuencia en el main
*/
Jugador::Jugador(){ veoPelota=false;}
Jugador::Jugador(int argc, char *argv[])
{
    thread_flag=false;
    veoPelota=false;
    pthread_mutex_init (&this->_mutex, (pthread_mutexattr_t*) NULL);
    cliente.checkConnection(argc);
    cliente.socket(argv);
    recibir.start(this);
    cliente.enviar("(init Grupo_3)");
    thread_flag=false;
    usleep(15000);
    thread_flag=false;
    numero=datos.getNumero();
    cout<<"Jugador con el dorsal "<<numero<<" juega en el lado "<<datos.getSide()<<endl;
    //datos.Seeinst["ball"].setDir(inicial);
    //datos.Seeinst["ball"].setDist(inicial);
}




void Jugador::setnumero(int Nnumero)
{
    numero = Nnumero;
}

int Jugador::getnumero()
{
    return numero;
}

void Jugador::setalpha(double num)
{
    alpha=num;
}

double Jugador::getalpha()
{
    return alpha;
}

void Jugador::comprobar_pelota(string h)
{
    if (h.find("see")!=string::npos && h.find("ball")!=string::npos)
        veoPelota=true;
    else
        if (h.find("see")!=string::npos && h.find("ball")==string::npos)
            veoPelota=false;
}

/** La función interpretar se encarga de recibir la cadena
  * (esto lo haremos con un thread) enviada por el servidor y colocar cada
  * variable en el struct correspondiente
  * Descomponemos la cadena y almacenamos las variables en los structs.
  * Para descomponerla buscaremos los parentesis (funcion leer) y extraemos
  * la informacion (con un switch la colocamos). */

void Jugador::interpretar(string h)
{
    parser.separardatos(h,datos);
    comprobar_pelota(h);
    setPosicion(h);
}


bool Jugador::golpear(int pot, double dir)
{
    msg.str("");
    if((0 < datos.Seeinst["ball"].getDist() < 0.7) && (datos.Seeinst["ball"].getDist()!=-200))
    {
        cout<<"----------------GOLPEO---------------"<<endl;
        msg << "(kick " << pot << " " << dir << ")";
        return true;
    }
    else
    {
        //cout<<datos.Seeinst["ball"].getDist()<<endl;
        return false;
    }
}

void Jugador::mover(double pot)
{
    msg.str("");//BORRAMOS EL CONTENIDO PORQUE SI NO SE AÑADE AL FINAL
    if (pot > 100 || pot < 0)
        pot = 100;
    msg<<"(dash "<<pot<<")";
}

void Jugador::girar(double ang) //VA EN FUNCION DEL MOMENTO. LE PASAMOS EL ANGULO QUE QUEREMOS GIRAR
{
    double momento;
    momento=ang*(1.0+5*(datos.Senseinst["speed"].getValue1()));
    msg.str("");
    if (momento<-180)
        momento=-180;
    if (momento>180)
        momento=180;
    msg<<"(turn "<<momento<<")";

}

void Jugador::mirar(double ang)
{
    msg.str("");
    if (ang<-180)
        ang=-180;
    if (ang>180)
        ang=180;
    msg<<"(turn_neck "<<ang<<")";
}

void Jugador::colocar(double x, double y)
{
    msg.str("");
    if(x<(-52.5) || x>(52.5))
        cout<<"Imposible mover al jugador, coordenada X incorrecta"<<endl;
    if(y<-34 || y>34)
        cout<<"Imposible mover al jugador, coordenada Y incorrecta"<<endl;
    msg<<"(move "<<x<<" "<<y<<")";
    pos_inicial.setX(x); /* PROBLEMA!! LA POSICION INICIAL ES LA DE SAQUE DE CENTRO */
    pos_inicial.setY(y); /* SI HACEMOS UN COLOCAR PARA UN SAQUE DE BANDA CAMBIARA LA POS_INICIAL */
}

/** La funcion buscar pelota devuelve false si no esta viendola y true si la ve*/
bool Jugador::buscarPelota()
{
    if (veoPelota)
    {
        if (-5 < datos.Seeinst["ball"].getDir() && datos.Seeinst["ball"].getDir() < 5)
            return true;
        else
        {
            while (5 < datos.Seeinst["ball"].getDir() || datos.Seeinst["ball"].getDir() < -5)
            {
                girar (datos.Seeinst["ball"].getDir());
                usleep(15000);
            }
            return true;
        }
    }
    else
    {
        girar(55);
        usleep(15000);
        return false;
    }

}

void Jugador::seguirPelota (bool zonaBalon)
{
    if (buscarPelota() ==true && zonaBalon ==true)
    {
        double velocidad = datos.Seeinst["ball"].getDist()*10;
        mover(velocidad);
        usleep(15000);
    }
}

/** para correr con el balon, damos golpes flojos al balon si podemos y, cuando no, corremos */
void Jugador::correr()
{
    if(golpear(10,0))
        usleep(15000);
    mover(70);
    usleep(15000);
}

void Jugador :: buscarIndicador(string indicador)
{
    bool find = false;
    while (!find)
    {
        if(cliente.getSbuffer().find("see")!=string::npos && cliente.getSbuffer().find(indicador)!=string::npos)
        {
            while (5 < datos.Seeinst[indicador].getDir() < -5)
            {
                girar(datos.Seeinst[indicador].getDir());
                usleep(15000);
            }
            find = true;
        }
        else
        {
            girar(20);
            find = false;
            usleep(15000);
        }
    }
}

void Jugador::esperarInicio()
{
    while(datos.Hearinst["referee"].getinstruction() != "kick_off")
    {
        thread_flag = false;
        usleep(15000);
    }
    enviar.start(this);
}

void Jugador::setPosicion(string h)
{
    double linedir, flagdir,flagdist=200,flag_x,flag_y,abs_x,abs_y, signo;
    if(h.find("see")!=string::npos)
    {
        if (h.find("(line r)")!=string::npos)
        {
            linedir = 90  + datos.Seeinst["line r"].getDir();

            if (datos.Seeinst["line r"].getDir()>0)

                linedir = 270 + datos.Seeinst["line r"].getDir();
        }

        if (h.find("(line l)")!=string::npos)
        {
            linedir = 90  + datos.Seeinst["line l"].getDir();

            if (datos.Seeinst["line l"].getDir()<0)

                linedir = 270  + datos.Seeinst["line l"].getDir();
        }

        if (h.find("(line t)")!=string::npos)
        {
            linedir = datos.Seeinst["line t"].getDir();

            if (datos.Seeinst["line t"].getDir()<0)

                linedir = 180 + datos.Seeinst["line t"].getDir();
        }

        if (h.find("(line b)")!=string::npos)
        {
            linedir = 180 + datos.Seeinst["line b"].getDir();

            if (datos.Seeinst["line b"].getDir()<0)

                linedir = 360 + datos.Seeinst["line b"].getDir();
        }


        if (h.find("(flag l b)")!=string::npos)
        {
            if(flagdist>datos.Seeinst["flag l b"].getDist())
            {
                flagdir= this->datos.Seeinst["flag l b"].getDir();
                flagdist=this->datos.Seeinst["flag l b"].getDist();
                flag_x=-52.5;
                flag_y=34;
            }
        }
        if (h.find("(flag l t)")!=string::npos)
        {
            if(flagdist>datos.Seeinst["flag l t"].getDist())
            {
                flagdir= this->datos.Seeinst["flag l t"].getDir();
                flagdist=this->datos.Seeinst["flag l t"].getDist();
                flag_x=-52.5;
                flag_y=-34;
            }
        }
        if (h.find("(flag c t)")!=string::npos)
        {
            if(flagdist>datos.Seeinst["flag c t"].getDist())
            {
                flagdir= this->datos.Seeinst["flag c t"].getDir();
                flagdist=this->datos.Seeinst["flag c t"].getDist();
                flag_x=0;
                flag_y=-34;
            }
        }
        if (h.find("(flag r t)")!=string::npos)
        {
            if(flagdist>datos.Seeinst["flag r t"].getDist())
            {
                flagdir= this->datos.Seeinst["flag r t"].getDir();
                flagdist=this->datos.Seeinst["flag r t"].getDist();
                flag_x=52.5;
                flag_y=-34;
            }
        }
        if (h.find("(flag r b)")!=string::npos)
        {
            if(flagdist>datos.Seeinst["flag r b"].getDist())
            {
                flagdir= this->datos.Seeinst["flag r b"].getDir();
                flagdist=this->datos.Seeinst["flag r b"].getDist();
                flag_x=52.5;
                flag_y=34;
            }
        }
        if (h.find("(flag c b)")!=string::npos)
        {
            if(flagdist>datos.Seeinst["flag c b"].getDist())
            {
                flagdir= this->datos.Seeinst["flag c b"].getDir();
                flagdist= this->datos.Seeinst["flag c b"].getDist();
                flag_x=0;
                flag_y=34;
            }
        }
        if (h.find("(goal l)")!=string::npos)
        {
            if(flagdist>datos.Seeinst["goal l"].getDist())
            {
                flagdir= this->datos.Seeinst["goal l"].getDir();
                flagdist=this->datos.Seeinst["goal l"].getDist();
                flag_x=-52.5;
                flag_y=0;
            }
        }
        if (h.find("(goal r)")!=string::npos)
        {
            if(flagdist>datos.Seeinst["goal r"].getDist())
            {
                flagdir= this->datos.Seeinst["goal r"].getDir();
                flagdist=this->datos.Seeinst["goal r"].getDist();
                flag_x=52.5;
                flag_y=0;
            }
        }
        if (h.find("(flag c)")!=string::npos)
        {
            if(flagdist>datos.Seeinst["flag c"].getDist())
            {
                flagdir= this->datos.Seeinst["flag c"].getDir();
                flagdist=this->datos.Seeinst["flag c"].getDist();
                flag_x=0;
                flag_y=0;
            }
        }

        alpha = (linedir - flagdir)*3.141592/180;

        abs_x=flag_x-(flagdist*(cos(alpha)));
        abs_y=flag_y+(flagdist*(sin(alpha)));

        posicion.setX(abs_x);
        posicion.setY(abs_y);
       // posicion.printPunto();
    }
}

void Jugador::goTo(Punto p)
{
    double dist,angle,rel_x,rel_y;

    /** Vamos a la posición deseada mientras no tengamos la pelota cerca */

    while(abs(p.getX()-posicion.getX())>2 || abs(p.getY()-posicion.getY())>2 ||
          (veoPelota && datos.Seeinst["ball"].getDist()>10))
    {

        /** Posición relativa a nosotros*/
        rel_x= p.getX()-posicion.getX();
        rel_y= p.getY()-posicion.getY();

        /** Distancia relativa a nosotros*/
        dist=sqrt(pow(rel_x,2)+pow(rel_y,2));

        /** Angulo relativo a nosotros en grados*/
        angle = (acos(rel_x/dist)-alpha)* 180 / 3.141592;

        if (5 < angle || angle < -5)
        {
            girar(angle);
            usleep(15000);
        }
        mover(80);
        usleep(15000);
    }

}

void Jugador::goTo(double x, double y)
{
    double dist,angle,rel_x,rel_y;

    /** Vamos a la posición deseada mientras no tengamos la pelota cerca */

    while(abs(x-posicion.getX())>2 || abs(y-posicion.getY())>2 ||
          (veoPelota && datos.Seeinst["ball"].getDist()>10))
    {

        /** Posición relativa a nosotros*/
        rel_x= x -posicion.getX();
        rel_y= y -posicion.getY();

        /** Distancia relativa a nosotros*/
        dist=sqrt(pow(rel_x,2)+pow(rel_y,2));

        /** Angulo relativo a nosotros en grados*/
        angle = (acos(rel_x/dist)-alpha)* 180 / 3.141592;

        if (5 < angle || angle < -5)
        {
            girar(angle);
            usleep(15000);
        }
        mover(80);

    }
}

/** Con esta función devolvemos un numero entero según sea la accion indicada por el arbitro. Este
  * numero lo utilizaremos despues para colocar a los jugadores según sea necesario*/
int Jugador::hearReferee()
{
    bool mySide;
    string instruction,side;
    if ((datos.hearEvent == true) && (datos.getultimaCadena().find("referee")!=string::npos))
    {
        instruction = datos.Hearinst["referee"].getinstruction();
        if (side == datos.Hearinst["referee"].getside())
            mySide = true;
        else
            mySide = false;

        if (instruction == "kick_off")
        {
            if (mySide)
                return 1;  //1 si saca de centro nuestro equipo
            else
                return 2;  //2 si saca de centro el equipo contrario
        }

        if (instruction == "kick_in")
        {
            if (mySide)
                return 3; //3 si saca de banda nuestro equipo
            else
                return 4; //4 si saca de banda el equipo contrario
        }

        if (instruction == "free_kick")
        {
            if(mySide)
                return 5; //5 si saca la falta mi equipo
            else
                return 6; //6 si saca la falta el quipo contrario
        }

        if (instruction == "corneer_kick")
        {
            if(mySide)
                return 7; //7 si saca de corner mi equipo
            else
                return 8; //8 si saca el corner el equio contrario
        }

        if (instruction == "goal_kick")
        {
            if (mySide)
                return 9; //9 Si saca de porteria mi equipo
            else
                return 10; //10 si saca de porteria el equipo contrario
        }

        if (instruction == "goal")
            return 11; //11 si hay gol

        if (instruction == "offside")
        {
            if (mySide)
                return 12; //12 si el fuera de juego es del otro equipo
            else
                return 13; //13 si el fuera de juego es de mi equipo
        }

        if(instruction == "half_time")
        {
            if (datos.getSide() == "l")
                datos.setSide("r");
            else
                datos.setSide("l");
            return 14; //14 despues de cambiar el lado de juego en el descanso
        }
    }
    return 0;
}
